#include "stdafx.h"
#include <iostream>
#include<fstream>

#include"../db/db_connection.h"
#include"../db/generic_table.h"

using namespace std;
using namespace uhdpbs::db;

string OutputTableCPP(string t) {
	string ret = "";
	ret += "#include\"" + t + "_table.h\"\n";
	ret += "#include\"" + t + "_row.h\"\n";
	ret += "\n";
	ret += "using namespace std;\n";
	ret += "using namespace uhdpbs::db;\n";
	ret += "\n";
	ret += "namespace uhdpbs {\n";
	ret += "	namespace generated {\n";
	ret += "		" + t + "_table::" + t + "_table(uhdpbs::db::connection* conn) : table(conn) { }\n";
	ret += "		" + t + "_table::~" + t + "_table() { }\n";
	ret += "		string " + t + "_table::get_name() { return string(\"" + t + "\"); }\n";
	ret += "		row " + t + "_table::create_new_row(string_string_map originals) {\n";
	ret += "			row rNew = " + t + "_row(originals, this);\n";
	ret += "			return rNew;\n";
	ret += "		}\n";
	ret += "	}\n";
	ret += "}\n";
	return ret;
}
string OutputTableH(string t) {
	string ret = "";
	ret += "#pragma once\n";
	ret += "#include\"..\\db\\db_connection.h\"\n";
	ret += "#include\"..\\db\\db_table.h\"\n";
	ret += "#include\"..\\db\\db_row.h\"\n";
	ret += "\n";
	ret += "namespace uhdpbs {\n";
	ret += "	namespace generated {\n";
	ret += "		class " + t + "_table : public uhdpbs::db::table {\n";
	ret += "		public:\n";
	ret += "			" + t + "_table(uhdpbs::db::connection* conn);\n";
	ret += "			~" + t + "_table();\n";
	ret += "\n";
	ret += "			std::string get_name();\n";
	ret += "			using table::create_new_row;\n";
	ret += "			uhdpbs::db::row create_new_row(uhdpbs::db::string_string_map originals);\n";
	ret += "		};\n";
	ret += "	}\n";
	ret += "}\n";
	return ret;
}

string OutputRowCPPTop(string t) {
	string ret = "";
	ret += "#include\"" + t + "_row.h\"\n";
	ret += "\n";
	ret += "#include<sstream>\n";
	ret += "\n";
	ret += "using namespace std;\n";
	ret += "using namespace uhdpbs::db;\n";
	ret += "\n";
	ret += "namespace uhdpbs {\n";
	ret += "	namespace generated {\n";
	ret += "		" + t + "_row::" + t + "_row(row& r) : row(r.get_originals(), r.get_table()) {\n";
	ret += "			this->mChanges = r.get_changes();\n";
	ret += "		}\n";
	ret += "		" + t + "_row::" + t + "_row(string_string_map originals, table* tbl) : row(originals, tbl) {}\n";
	ret += "		" + t + "_row::~" + t + "_row() {}\n";
	ret += "\n";
	return ret;
}
string OutputRowCPPColumn(string t, string c) {
	string ret = "";
	ret += "		string " + t + "_row::get_" + c + "() { return get_value(\"" + c + "\"); }\n";
	ret += "		void " + t + "_row::set_" + c + "(string val) { set_value(\"" + c + "\", val); }\n";
	return ret;
}
string OutputRowCPPBottom(string t) {
	string ret = "";
	ret += "	}\n";
	ret += "}\n";
	return ret;
}

string OutputRowHTop(string t) {
	string ret = "";
	ret += "#pragma once\n";
	ret += "#include\"..\\db\\db_row.h\"\n";
	ret += "\n";
	ret += "namespace uhdpbs {\n";
	ret += "	namespace generated {\n";
	ret += "		class " + t + "_row : public uhdpbs::db::row {\n";
	ret += "		public:\n";
	ret += "			" + t + "_row(row& r);\n";
	ret += "			" + t + "_row(uhdpbs::db::string_string_map originals, uhdpbs::db::table* tbl);\n";
	ret += "			~" + t + "_row();\n";
	ret += "\n";
	return ret;
}
string OutputRowHColumn(string t, string c) {
	string ret = "";
	ret += "			std::string get_" + c + "();\n";
	ret += "			void set_" + c + "(std::string val);\n";
	return ret;
}
string OutputRowHBottom(string t) {
	string ret = "";
	ret += "		};\n";
	ret += "	}\n";
	ret += "}\n";
	return ret;
}

string OutputMenuH() {
	string ret = "";
	ret += "#pragma once\n";
	ret += "\n";
	ret += "#include \"../menu/Header.h\"\n";
	ret += "#include \"../menu/Menu.h\"\n";
	ret += "#include \"../db/db_row.h\"\n";
	ret += "\n";
	return ret;
}
string OutputMenuHIncludes(string t) {
	string ret = "";
	ret += "#include \"../db_generator/" + t + "_table.h\"\n";
	ret += "#include \"../db_generator/" + t + "_row.h\"\n";
	return ret;
}
string OutputMenuHUpper() {
	string ret = "";
	ret += "\n";
	ret += "namespace uhdpbs {\n";
	ret += "	namespace menu {\n";
	ret += "		class generated {\n";
	ret += "		public:\n";
	ret += "			static void edit_row(uhdpbs::db::row* r);\n";
	ret += "\n";
	return ret;
}
string OutputMenuHList(string t) {
	string ret = "";
	ret += "			static void " + t + "_list(uhdpbs::generated::" + t + "_table* tbl);\n";
	return ret;
}
string OutputMenuHBottom() {
	string ret = "";
	ret += "		};\n";
	ret += "	}\n";
	ret += "}\n";
	return ret;
}

string OutputMenuCPP() {
	string ret = "";
	ret += "#include \"generated_menu.h\"\n";
	ret += "\n";
	ret += "using namespace std;\n";
	ret += "using namespace uhdpbs::db;\n";
	ret += "using namespace uhdpbs::generated;\n";
	ret += "\n";
	ret += "namespace uhdpbs {\n";
	ret += "	namespace menu {\n";
	ret += "		void generated::edit_row(row* r) {\n";
	ret += "			int iStartPosition = 1;\n";
	ret += "			while(true) {\n";
	ret += "				string sTitle = r->get_table()->get_connection()->get_user_freidnly_name(r->get_table()->get_name()) + \" Record\";\n";
	ret += "				string_vector* psvColumns = r->get_table()->get_columns();\n";
	ret += "\n";
	ret += "				Menu mnu = Menu(sTitle, \" > \", \"\");\n";
	ret += "\n";
	ret += "				for(int cnt = 0; cnt < psvColumns->size(); cnt++) {		\n";
	ret += "					string sColName = (*psvColumns)[cnt];\n";
	ret += "					string sNiceName = r->get_table()->get_connection()->get_user_freidnly_name(sColName);\n";
	ret += "					string sValue = r->get_value(sColName);\n";
	ret += "\n";
	ret += "					mnu.AddOption(sNiceName + \": \" + sValue);\n";
	ret += "				}\n";
	ret += "\n";
	ret += "				mnu.AddOption(\"Reset Record to Original Values\");\n";
	ret += "				mnu.AddOption(\"Delete Record and Return\");\n";
	ret += "				mnu.AddOption(\"Return to Previous Menu\");\n";
	ret += "\n";
	ret += "				int iSelection = mnu.Play(iStartPosition);\n";
	ret += "				VP_ClearScreen();\n";
	ret += "				if(iSelection <= psvColumns->size()) {\n";
	ret += "					string sColName = (*psvColumns)[iSelection - 1];\n";
	ret += "					if(sColName == \"id\") {\n";
	ret += "						cout << \"The ID will be assigned when the record is saved.\" << endl;\n";
	ret += "						cout << \"Press enter to continue...\";\n";
	ret += "						cin.get();\n";
	ret += "					}else {\n";
	ret += "						string sNiceName = r->get_table()->get_connection()->get_user_freidnly_name(sColName);\n";
	ret += "\n";
	ret += "						cout << sNiceName << \": \";\n";
	ret += "\n";
	ret += "						string sNewValue = \"\";\n";
	ret += "						char pcBuffer[1024];\n";
	ret += "						cin.getline(pcBuffer, sizeof(pcBuffer));\n";
	ret += "\n";
	ret += "						r->set_value(sColName, pcBuffer);\n";
	ret += "					}\n";
	ret += "				} else if(iSelection == psvColumns->size() + 1) {\n";
	ret += "					r->reset();\n";
	ret += "				} else if(iSelection == psvColumns->size() + 2) {\n";
	ret += "					r->is_deleted(true);\n";
	ret += "					return;\n";
	ret += "				} else if(iSelection == psvColumns->size() + 3) {\n";
	ret += "					return;\n";
	ret += "				} else {\n";
	ret += "					cout << \"Invalid selection\" << endl;\n";
	ret += "					cout << \"Press enter to continue...\";\n";
	ret += "					cin.get();\n";
	ret += "				}\n";
	ret += "\n";
	ret += "				iStartPosition = iSelection;\n";
	ret += "			}\n";
	ret += "		}\n";
	ret += "\n";
	return ret;
}
string OutputMenuCPPMiddle(string t) {
	string ret = "";
	ret += "		void generated::" + t + "_list(" + t + "_table* tbl) {\n";
	ret += "			int iStartPosition = 1;\n";
	ret += "			while(true) {\n";
	ret += "				Menu mnu = Menu(\"Patient List\", \" > \", \"\");\n";
	ret += "				for(int cnt = 0; cnt < tbl->get_rows()->size(); cnt++) {\n";
	ret += "					" + t + "_row r = (" + t + "_row) (*tbl->get_rows())[cnt];\n";
	ret += "\n";
	ret += "					// !!! YOU NEED TO SET THE DISPLAY !!!\n";
	ret += "					string sDisplay = \"!!! YOU NEED TO SET THE DISPLAY FOR THE LIST !!!\";\n";
	ret += "					// !!! YOU NEED TO SET THE DISPLAY !!!\n";
	ret += "\n";
	ret += "					mnu.AddOption(sDisplay);\n";
	ret += "				}\n";
	ret += "\n";
	ret += "				mnu.AddOption(\"Add New Record\");\n";
	ret += "				mnu.AddOption(\"Return to Previous Menu\");\n";
	ret += "\n";
	ret += "				int iSelection = mnu.Play(iStartPosition);\n";
	ret += "				VP_ClearScreen();\n";
	ret += "				if(iSelection <= tbl->get_rows()->size()) {\n";
	ret += "					row r = (*tbl->get_rows())[iSelection - 1];\n";
	ret += "					edit_row(&r);\n";
	ret += "					(*tbl->get_rows())[iSelection - 1] = r;\n";
	ret += "					tbl->save();\n";

	ret += "					if(tbl->get_connection()->get_error().length() > 0) {\n";
	ret += "						cout << tbl->get_connection()->get_error() << endl;\n";
	ret += "						cout << \"Press enter to continue...\";\n";
	ret += "						cin.get();\n";
	ret += "						tbl->get_connection()->clear_error();\n";
	ret += "					}\n";

	ret += "					tbl->load();\n";
	ret += "					if(tbl->get_connection()->get_error().length() > 0) {\n";
	ret += "						cout << tbl->get_connection()->get_error() << endl;\n";
	ret += "						cout << \"Press enter to continue...\";\n";
	ret += "						cin.get();\n";
	ret += "						tbl->get_connection()->clear_error();\n";
	ret += "					}\n";
	ret += "				} else if(iSelection == tbl->get_rows()->size() + 1) {\n";
	ret += "					row r = tbl->create_new_row();\n";
	ret += "					edit_row(&r);\n";
	ret += "					tbl->get_rows()->push_back(r);\n";
	ret += "					tbl->save();\n";
	ret += "					if(tbl->get_connection()->get_error().length() > 0) {\n";
	ret += "						cout << tbl->get_connection()->get_error() << endl;\n";
	ret += "						cout << \"Press enter to continue...\";\n";
	ret += "						cin.get();\n";
	ret += "						tbl->get_connection()->clear_error();\n";
	ret += "					}\n";
	ret += "					tbl->load();\n";
	ret += "					if(tbl->get_connection()->get_error().length() > 0) {\n";
	ret += "						cout << tbl->get_connection()->get_error() << endl;\n";
	ret += "						cout << \"Press enter to continue...\";\n";
	ret += "						cin.get();\n";
	ret += "						tbl->get_connection()->clear_error();\n";
	ret += "					}\n";
	ret += "				} else if(iSelection == tbl->get_rows()->size() + 2) {\n";
	ret += "					return;\n";
	ret += "				} else {\n";
	ret += "					cout << \"Invalid selection\" << endl;\n";
	ret += "					cout << \"Press enter to continue...\";\n";
	ret += "					cin.get();\n";
	ret += "				}\n";
	ret += "\n";
	ret += "				iStartPosition = iSelection;\n";
	ret += "			}\n";
	ret += "		}\n";
	return ret;
}
string OutputMenuCPPBottom() {
	string ret = "";
	ret += "	}\n";
	ret += "}\n";
	return ret;
}


int _tmain(int argc, _TCHAR* argv[]) {
	connection dbConn = connection();
	if(!dbConn.open(string("localhost"), string("uhdpbs_db"), string("uhdpbs"), string("password1234"))) {
		//cout << "Could not open database connection!";
		return -1;
	}

	generic_table tbl = generic_table(&dbConn);
	tbl.set_name("INFORMATION_SCHEMA.TABLES");
	tbl.set_sql("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='uhdpbs_db';");
	tbl.load();

	ofstream ofMenuH = ofstream();
	ofMenuH.open("generated_menu.h", ios::out | ios::trunc);
	ofMenuH << OutputMenuH();

	ofstream ofMenuCPP = ofstream();
	ofMenuCPP.open("generated_menu.cpp", ios::out | ios::trunc);
	ofMenuCPP << OutputMenuCPP();

	for(int cnt = 0; cnt < tbl.get_rows()->size(); cnt++) {
		row r = (*tbl.get_rows())[cnt];

		string sTable = r.get_value("TABLE_NAME");
		generic_table gtbl = generic_table(&dbConn);
		gtbl.set_name(sTable);
		dbConn.load_meta_data(&gtbl);

		ofMenuH << OutputMenuHIncludes(sTable);

		ofMenuCPP << OutputMenuCPPMiddle(sTable);

		string sTableH = sTable + "_table.h";
		ofstream ofTableH = ofstream();
		ofTableH.open(sTableH.c_str(), ios::out | ios::trunc);
		ofTableH << OutputTableH(sTable);
		ofTableH.close();

		string sTableCPP = sTable + "_table.cpp";
		ofstream ofTableCPP = ofstream();
		ofTableCPP.open(sTableCPP.c_str(), ios::out | ios::trunc);
		ofTableCPP << OutputTableCPP(sTable);
		ofTableCPP.close();

		string sRowH = sTable + "_row.h";
		ofstream ofRowH = ofstream();
		ofRowH.open(sRowH.c_str(), ios::out | ios::trunc);
		ofRowH << OutputRowHTop(sTable);

		string sRowCPP = sTable + "_row.cpp";
		ofstream ofRowCPP = ofstream();
		ofRowCPP.open(sRowCPP.c_str(), ios::out | ios::trunc);
		ofRowCPP << OutputRowCPPTop(sTable);

		string_vector* svColumns = gtbl.get_columns();
		for(int cnt = 0; cnt < svColumns->size(); cnt++) {
			string sColumn = (*svColumns)[cnt];

			ofRowCPP << OutputRowCPPColumn(sTable, sColumn);
			ofRowH << OutputRowHColumn(sTable, sColumn);
		}

		ofRowCPP << OutputRowCPPBottom(sTable);
		ofRowCPP.close();

		ofRowH << OutputRowHBottom(sTable);
		ofRowH.close();
	}	


	ofMenuH << OutputMenuHUpper();

	for(int cnt = 0; cnt < tbl.get_rows()->size(); cnt++) {
		row r = (*tbl.get_rows())[cnt];

		string sTable = r.get_value("TABLE_NAME");

		ofMenuH << OutputMenuHList(sTable);
	}

	ofMenuH << OutputMenuHBottom();
	ofMenuH.close();

	ofMenuCPP << OutputMenuCPPBottom();
	ofMenuCPP.close();
}